package com.reporting;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ApplicationErrorReport;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.os.Build;
import android.os.Debug;
import android.util.Log;
import android.view.View;
import android.view.Window;


public class ReportHandler {

    private static final String[] EVENT_LOG_CMD = { "logcat", "-d",
                "-b", "events", "-v", "time" };

    private static volatile boolean mCrashing = false;

    private static Context sAppContext;

    private static String sEmailAddress;

    private static final String[] SYSTEM_LOG_CMD = { "logcat", "-d",
                "-v", "time" };

    private static final String TAG = ReportHandler.class.getSimpleName();

    public static String getEmailAddress() {

        return sEmailAddress;
    }

    public static Bitmap getScreenshot() {

        Activity activity = ReportingActivity.getForegroundInstance();
        if (activity == null) {
            return null;
        }
        Window window = activity.getWindow();
        if (window == null) {
            return null;
        }
        View view = window.getDecorView();
        if (view == null) {
            return null;
        }
        view.buildDrawingCache();
        Bitmap cache = view.getDrawingCache();
        Bitmap screenshot = cache.copy(cache.getConfig(), false);
        cache = null;
        if (!view.isDrawingCacheEnabled()) {
            view.destroyDrawingCache();
        }
        return screenshot;
    }

    public static void install(Context context, String emailAddress) {

        sAppContext = context.getApplicationContext();
        sEmailAddress = emailAddress;

        // NOTE: It does not generate crash reports when you are debugging your
        // app.
        if (!Debug.waitingForDebugger()
                    && !Debug.isDebuggerConnected()) {
            Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
        }
    }

    public static String saveEventLog() {

        return captureCommand("event-log", EVENT_LOG_CMD);
    }

    public static String saveScreenShot(Bitmap bitmap) {

        FileOutputStream stream = null;
        try {
            File temp = File.createTempFile("crash-report", ".jpg");
            stream = new FileOutputStream(temp);
            bitmap.compress(CompressFormat.JPEG, 80, stream);
            return temp.getAbsolutePath();
        }
        catch (IOException e) {
            Log.e(TAG, e.getMessage(), e);
        }
        finally {
            if (stream != null) {
                try {
                    stream.close();
                }
                catch (IOException e) {
                    Log.e(TAG, e.getMessage(), e);
                }
            }
        }
        return null;
    }

    public static String saveSystemLog() {

        return captureCommand("system-log", SYSTEM_LOG_CMD);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public static void showDefaultReportActivity(Context context, Throwable th) {

        String packageName = context.getPackageName();
        PackageManager pm = context.getPackageManager();

        // Not perfect.. but it'll have to do.
        ApplicationErrorReport report = new ApplicationErrorReport();
        report.installerPackageName = pm.getInstallerPackageName(packageName);
        report.packageName = packageName;
        report.processName = packageName;
        report.time = System.currentTimeMillis();
        report.systemApp = false;
        report.type = ApplicationErrorReport.TYPE_CRASH;
        report.crashInfo = new ApplicationErrorReport.CrashInfo(th);

        sAppContext.startActivity(new Intent(Intent.ACTION_APP_ERROR).setPackage("com.google.android.feedback").putExtra(Intent.EXTRA_BUG_REPORT, report).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
    }

    private static String captureCommand(String filePrefix, String[] command) {

        Process process = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            File temp = File.createTempFile(filePrefix, ".txt");
            fos = new FileOutputStream(temp);
            process = new ProcessBuilder(command).redirectErrorStream(true).start();
            is = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos));
            String line;
            while ((line = reader.readLine()) != null) {
                writer.append(line).append('\n');
            }
            writer.flush();

            return temp.getAbsolutePath();
        }
        catch (IOException e) {
            Log.e(TAG, e.getMessage(), e);
        }
        finally {
            if (process != null) {
                process.destroy();
            }
            if (fos != null) {
                try {
                    fos.close();
                }
                catch (IOException e) {
                    Log.e(TAG, e.getMessage(), e);
                }
            }
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException e) {
                    Log.e(TAG, e.getMessage(), e);
                }
            }
        }

        return null;
    }

    private static class UncaughtHandler implements UncaughtExceptionHandler {

        @Override
        public void uncaughtException(Thread thread, Throwable ex) {

            try {
                // Don't re-enter -- avoid infinite loops if crash-reporting
                // crashes.
                if (mCrashing) {
                    return;
                }
                mCrashing = true;
                Log.e(TAG, "FATAL EXCEPTION: " + thread.getName(), ex);
                // Attempt to save a screenshot (no permissions required!)
                String screenshot = null;
                Bitmap bm = ReportHandler.getScreenshot();
                if (bm != null) {
                    screenshot = ReportHandler.saveScreenShot(bm);
                    bm.recycle();
                }
                // Bring up crash dialog
                sAppContext.startActivity(ReportActivity.createIntent(sAppContext, ex, screenshot));
            }
            catch (Throwable t2) {
                try {
                    Log.e(TAG, "Error reporting crash", t2);
                }
                catch (Throwable t3) {
                    // Even Log.e() fails! Oh well.
                }
            }
            finally {
                // Try everything to make sure this process goes away.
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(10); // magic numbers!
            }
        }
    }
}
